use crate::home_page::Home;
use crate::page::Page;
use ratatui::{
    backend::CrosstermBackend,
    crossterm::{
        event::{self, Event, KeyCode},
        terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
        ExecutableCommand,
    },
    layout::{Constraint, Layout},
    prelude::*,
    widgets::*,
    CompletedFrame, Frame, Terminal,
};
use std::{
    borrow::{Borrow, BorrowMut},
    io::{self, stdout},
    sync::Arc,
};
use tokio::sync::Mutex;
use tool::tool_date::DateTime;
use tool::tool_result::Error;

static REFRESH_FAST: u64 = 10;
static REFRESH_SLOW: u64 = 1000 * 60;

pub struct App {
    pub page: Page,
    pub home: Arc<tokio::sync::RwLock<Home>>,

    pub cur_msg: Arc<tokio::sync::RwLock<Option<Message>>>,
    pub msg_list: Arc<tokio::sync::RwLock<Vec<String>>>,

    pub refresh_mill: u64,

    pub need_clear_screen: Arc<tokio::sync::RwLock<bool>>,
    pub dont_control:Arc<tokio::sync::Mutex<bool>>,

    ///不能继续使用
    pub stop:tokio::sync::Mutex<bool>,
    pub stop2:tokio::sync::Mutex<bool>
}

#[derive(Debug, Clone)]
pub struct Message {
    pub msg: String,
    pub start_date_time: DateTime,
}
impl Message {
    pub fn new(msg: String) -> Self {
        let date_time = DateTime::now();
        Message {
            msg,
            start_date_time: date_time,
        }
    }
}

impl App {
    pub fn new_home() -> Self {
        App {
            page: Page::Home,
            home: Arc::new(tokio::sync::RwLock::new(Home::new())),

            cur_msg: Arc::new(tokio::sync::RwLock::new(None)),
            msg_list: Arc::new(tokio::sync::RwLock::new(vec![])),

            refresh_mill: REFRESH_SLOW,

            need_clear_screen: Arc::new(tokio::sync::RwLock::new(false)),
            dont_control:Arc::new(tokio::sync::Mutex::new(false)),

            stop:tokio::sync::Mutex::new(false),
            stop2:tokio::sync::Mutex::new(false),
        }
    }
    ///唯一按键入口
    pub async fn key_event(app: Arc<App>, key_code: KeyCode) -> Result<(), Error> {
        {
            if *(app.stop.lock().await){
                return Ok(());
            }
        }
        if let Page::Home = app.page {
            match key_code {
                KeyCode::Down => {
                    Home::next(app.clone()).await;
                }
                KeyCode::Up => {
                    Home::pre(app.clone()).await;
                }
                KeyCode::Enter => {
                    Home::handle(app.clone()).await?;
                }
                KeyCode::Char('q') => {
                    Home::stop_backup_mysql(app.clone()).await;
                }
                _ => (),
            }
        }
        Ok(())
    }
    pub async fn push_msg_handle(app: Arc<App>) -> Result<(), Error> {
        let mut cur_msg = app.cur_msg.write().await;
        let mut msg_list = app.msg_list.write().await;

        if cur_msg.is_some() {
            if msg_list.len() != 0 {
                *cur_msg = None;
            } else {
                let start_date_time = cur_msg.as_ref().unwrap().start_date_time.clone();
                let diff_mill = DateTime::now().get_diff_time_mill(&start_date_time);
                if diff_mill > 2000 {
                    *cur_msg = None;
                }
            }
        }
        if cur_msg.is_none() {
            if msg_list.len() != 0 {
                let first_msg = msg_list[0].clone();
                msg_list.remove(0);
                *cur_msg = Some(Message::new(first_msg));
            }
        }
        Ok(())
    }

    pub async fn push_msg<T: Into<String>>(app: Arc<App>, msg: T) {
        {
            let mut msg_list = app.msg_list.write().await;
            msg_list.push(msg.into());
        }
    }

    pub async fn draw<B: Backend>(app: Arc<App>, terminal: &mut Terminal<B>) -> Result<(), Error> {
        {
            if *(app.stop2.lock().await){
                return Ok(());
            }
        }
        if let Page::Home = app.page {
            Self::draw_home(app.clone(), terminal).await?;
            return Ok(());
        }
        Ok(())
    }

    pub async fn draw_home<'a, B: Backend>(
        app: Arc<App>,
        terminal: &'a mut Terminal<B>,
    ) -> Result<(), Error> {
        let mut top_msg_constraint = Constraint::Min(0);
        let mut backup_progress_constraint = Constraint::Min(0);
        let mut title = Paragraph::new("".white().bold());
        let mut cur_msg: Option<Message> = None;
        let mut home_list: Vec<String> = vec![];
        let mut backup_progress: Option<Gauge> = None;
        let mut index = 0;
        {
            let _home = app.home.read().await;
            let home_read = _home;

            let mut _title = home_read.title.clone();
            if home_read.sub_title != "".to_string() {
                _title = format!("{} - {}", _title, home_read.sub_title);
            }

            title = Paragraph::new(_title.clone().white().bold());

            if home_read.cur_backup_mysql_config.is_some() {
                title = Paragraph::new(_title.white().red());

                let cur_backup_mysql_config = home_read.cur_backup_mysql_config.clone().unwrap();

                if !cur_backup_mysql_config.zip_info.is_some() {
                    let rate = cur_backup_mysql_config.ok_table_list.len() as f64
                        / cur_backup_mysql_config.all_table_list.len() as f64;
                    let gauge = Gauge::default()
                        .block(
                            Block::default()
                                .borders(Borders::ALL)
                                .title("使劲备份中..."),
                        )
                        .gauge_style(
                            ratatui::style::Style::default().fg(ratatui::style::Color::Green),
                        )
                        .percent((rate * 100.0) as u16);
                    backup_progress = Some(gauge);
                    backup_progress_constraint = Constraint::Length(15);
                } else {
                    let zip_info = cur_backup_mysql_config.zip_info.unwrap().clone();
                    let rate = zip_info.cur_size as f64 / zip_info.all_size as f64;
                    let gauge = Gauge::default()
                        .block(Block::default().borders(Borders::ALL).title(format!(
                            "使劲压缩中({}/{})...",
                            zip_info.cur_size, zip_info.all_size
                        )))
                        .gauge_style(
                            ratatui::style::Style::default().fg(ratatui::style::Color::Green),
                        )
                        .percent((rate * 100.0) as u16);
                    backup_progress = Some(gauge);
                    backup_progress_constraint = Constraint::Length(15);
                }
            }

            if app.cur_msg.read().await.is_some() {
                top_msg_constraint = Constraint::Length(35);
            }

            let _cur_msg = app.cur_msg.read().await;
            if _cur_msg.is_none() {
                cur_msg = None;
            } else {
                let a = _cur_msg.as_ref().unwrap().clone();
                cur_msg = Some(a);
            }

            if cur_msg.is_none() && backup_progress.is_some() {
                //没有字，但是有进度，为了让进度不会超出原来的高度，设置下字的高度
                top_msg_constraint = Constraint::Length(35);
            }

            home_list = home_read.list.clone();

            index = home_read.index;
        }

        let mut need_clear_screen = false;
        {
            let _need_clear_screen = app.need_clear_screen.read().await;
            need_clear_screen = _need_clear_screen.clone();
        }
        if need_clear_screen {
            {
                let mut _need_clear_screen = app.need_clear_screen.write().await;
                match terminal.clear() {
                    Ok(e) => e,
                    Err(e) => return Err(Error::new(e.to_string())),
                }
                *_need_clear_screen = false;
            }
        }

        {
            if *(app.stop.lock().await){
                *(app.stop2.lock().await)=true;
            }
        }

        let re = terminal.draw(|frame| {
            let [top, content] =
                Layout::vertical([Constraint::Length(50), Constraint::Length(100)])
                    .areas(frame.area());

            let [top_top, top_msg, top_backup_progress] = Layout::vertical([
                Constraint::Length(25),
                top_msg_constraint,
                backup_progress_constraint,
            ])
            .areas(top);

            frame.render_widget(title.clone(), top_top);
            if cur_msg.is_some() {
                let title = Paragraph::new(cur_msg.as_ref().unwrap().msg.clone().white().bold());
                frame.render_widget(title.clone(), top_msg);
            }
            if backup_progress.is_some() {
                frame.render_widget(backup_progress.as_ref().unwrap(), top_backup_progress);
            }
            // 列表
            let items: Vec<ListItem> = home_list
                .iter()
                .enumerate()
                .map(|(i, ref item)| {
                    let mut style = Style::default();
                    if i == index as usize {
                        style = Style::default().fg(Color::Red);
                    }
                    ListItem::new(item.as_str()).style(style)
                })
                .collect();
            let block = Block::default().borders(Borders::ALL).title("请选择");
            let list = List::new(items).block(block).highlight_style(
                Style::default()
                    .bg(Color::LightBlue)
                    .add_modifier(Modifier::BOLD),
            );
            frame.render_widget(list, content);
        });
        match re {
            Ok(e) => return Ok(()),
            Err(e) => return Err(Error::new(e.to_string())),
        }
    }
}

impl App {
    pub async fn time_event(app: Arc<App>) -> Result<(), Error> {
        if let Page::Home =app.page{
            Home::time_event(app.clone()).await?;
        }
        Ok(())
    }
}
